using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Web.UI;
using System.Web;

namespace GAControl
{
    [ToolboxData("<{0}:GAControl runat=server></{0}:GAControl>")]
    public class GAControl : WebControl
    {
        private string _accountNumber;

        /// <summary>
        /// Account ID from the tracking code, in the format UA-xxxx-x
        /// </summary>
        [Bindable(true)]
        public string AccountNumber
        {
            get { return _accountNumber; }
            set { _accountNumber = value; }
        }

        private string _campaignSource = "", _campaignMedium = "", _campaignTerm = "", _campaignContent = "", _campaignName = "";
        private string _campaignSourceQS = "", _campaignMediumQS = "", _campaignTermQS = "", _campaignContentQS = "", _campaignNameQS = "";


        private string _urchinSource = "//www.google-analytics.com/urchin.js";
        /// <summary>
        /// Location of JavaScript file for Google Analytics, can be left default. Omitting the protocol (HTTP) means the browser will default to the host page protocol.
        /// </summary>
        [DefaultValue("//www.google-analytics.com/urchin.js")]
        public string UrchinSource
        {
            get { return _urchinSource; }
            set { _urchinSource = value; }
        }

        /// <summary>
        /// Encode strings for JavaScript
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private string Enc(string s)
        {
            if (s == null || s.Length == 0)
            {
                return "";
            }
            char c;
            int i;
            int len = s.Length;
            StringBuilder sb = new StringBuilder(len + 4);
            string t;

            for (i = 0; i < len; i += 1)
            {
                c = s[i];
                if ((c == '\\') || (c == '"') || (c == '\'') || (c == '>'))
                {
                    sb.Append('\\');
                    sb.Append(c);
                }
                else if (c == '\b')
                    sb.Append("\\b");
                else if (c == '\t')
                    sb.Append("\\t");
                else if (c == '\n')
                    sb.Append("\\n");
                else if (c == '\f')
                    sb.Append("\\f");
                else if (c == '\r')
                    sb.Append("\\r");
                else
                {
                    if (c < ' ')
                    {
                        //t = "000" + Integer.toHexString(c); 
                        string tmp = new string(c, 1);
                        t = "000" + int.Parse(tmp, System.Globalization.NumberStyles.HexNumber);
                        sb.Append("\\u" + t.Substring(t.Length - 4));
                    }
                    else
                    {
                        sb.Append(c);
                    }
                }
            }
            return sb.ToString();
        } 

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            // load GA JS
            writer.Write(string.Format("<script src=\"{0}\" type=\"text/javascript\"></script>\r\n", HttpUtility.HtmlEncode(_urchinSource)));
            // load Control JS
            writer.Write(string.Format("<script src=\"{0}\" type=\"text/javascript\"></script>\r\n", Page.ClientScript.GetWebResourceUrl(this.GetType(), "GAControl.links.js")));
            
            writer.Write("<script type=\"text/javascript\">\r\n//<!--\r\n");

            // set account ID
            writer.Write(string.Format("_uacct=\"{0}\";_udn='none';\r\n", Enc(_accountNumber)));

            // set campaign source properties
            if (_campaignSource != string.Empty && _campaignMedium != string.Empty && _campaignName != string.Empty)
            {
                string js = string.Format("GAControl_SetCampaign({0},{1},{2},{3},{4});\r\n",
                    Enc(_campaignSource), Enc(_campaignMedium), Enc(_campaignTerm), Enc(_campaignContent), Enc(_campaignName));
                writer.Write(js);
            }

            // initialise the tracker
            writer.Write("urchinTracker();\r\n");

            // trigger extra page hits
            foreach (string loc in _extraLocations)
            { 
                writer.Write(string.Format("urchinTracker('{0}');\r\n",Enc(loc)));
            }

            // pass cookie on links to other domains
            if (_extraDomains.Count > 0)
            {
                writer.Write(string.Format("_udn='none';_ulink=1;GAControl_AltSites(Array('{0}'));\r\n", String.Join("','", _extraDomains.ToArray())));
            }

            if (_transaction != null)
            {
                writer.Write(string.Format("GAControl_SetTrans('{0}');\r\n",Enc(_transaction.GetLines())));
            }

            writer.Write("//-->\r\n</script>");
        }

        private Transaction _transaction;
        /// <summary>
        /// E-commerce transaction details, GA must be in e-commerce tracking mode.
        /// </summary>
        public Transaction Transaction
        {
            get { return _transaction; }
            set { _transaction = value; }
        }


        #region Alternative Domains

        private List<String> _extraDomains = new List<string>();
        /// <summary>
        /// Add other URLs that are part of this site. Users cookies will be passed across in links and forms so the tracking session can carry across domains. The other site must be using the same GA account.
        /// </summary>
        /// <param name="Location">A full URL, any links to that URL and below will send the cookie details, eg. http://www.secondsite.com/</param>
        public void AddAlternativeURL(string URL)
        {
            _extraDomains.Add(Enc(URL));
        }

        #endregion

        #region Arbitary Locations

        private List<String> _extraLocations = new List<string>();
        /// <summary>
        /// Add locations to be saved as page hits, can be used to track events for conversion goals
        /// </summary>
        /// <param name="Location">Absolute path of location, eg. /event/download/</param>
        public void AddLocation(string Location)
        {
            _extraLocations.Add(Enc(Location));
        }

        #endregion

        #region Arbitary Campaign Sources

        /// <summary>
        /// Set campaign source values.
        /// </summary>
        /// <param name="CampaignName">To identify a specific product promotion or strategic campaign.</param>
        /// <param name="CampaignSource">To identify a search engine, newsletter name, or other source.</param>
        /// <param name="CampaignMedium">To identify a medium such as email or cost-per-click.</param>
        /// <param name="CampaignTerm">To note the keywords for this ad.</param>
        /// <param name="CampaignContent">To differentiate ads or links that point to the same URL.</param>
        public void SetSource(string CampaignName, string CampaignSource, string CampaignMedium, string CampaignTerm, string CampaignContent)
        {
            _campaignSource = CampaignSource;
            _campaignMedium = CampaignMedium;
            _campaignTerm = CampaignTerm;
            _campaignContent = CampaignContent;
            _campaignName = CampaignName;
        }

        /// <param name="CampaignName">To identify a specific product promotion or strategic campaign.</param>
        /// <param name="CampaignSource">To identify a search engine, newsletter name, or other source.</param>
        /// <param name="CampaignMedium">To identify a medium such as email or cost-per- click.</param>
        /// <param name="CampaignTerm">To note the keywords for this ad.</param>
        public void SetSource(string CampaignName, string CampaignSource, string CampaignMedium, string CampaignTerm)
        {
            SetSource(CampaignName, CampaignSource, CampaignMedium, CampaignTerm, "");
        }

        /// <param name="CampaignName">To identify a specific product promotion or strategic campaign.</param>
        /// <param name="CampaignSource">To identify a search engine, newsletter name, or other source.</param>
        /// <param name="CampaignMedium">To identify a medium such as email or cost-per- click.</param>
        public void SetSource(string CampaignName, string CampaignSource, string CampaignMedium)
        {
            SetSource(CampaignName, CampaignSource, CampaignMedium, "", "");
        }

        /// <summary>
        /// To identify a specific product promotion or strategic campaign.
        /// </summary>
        public string CampaignName
        {
            get { return _campaignName; }
            set { _campaignName = value; }
        }

        /// <summary>
        /// To differentiate ads or links that point to the same URL.
        /// </summary>
        public string CampaignContent
        {
            get { return _campaignContent; }
            set { _campaignContent = value; }
        }

        /// <summary>
        /// To note the keywords for this ad.
        /// </summary>
        public string CampaignTerm
        {
            get { return _campaignTerm; }
            set { _campaignTerm = value; }
        }

        /// <summary>
        /// To identify a medium such as email or cost-per-click.
        /// </summary>
        public string CampaignMedium
        {
            get { return _campaignMedium; }
            set { _campaignMedium = value; }
        }

        /// <summary>
        /// To identify a search engine, newsletter name, or other source.
        /// </summary>
        public string CampaignSource
        {
            get { return _campaignSource; }
            set { _campaignSource = value; }
        }

        #endregion

        #region Campaign Source Mapping

        /// <summary>
        /// Querystring item name to identify a specific product promotion or strategic campaign.
        /// </summary>
        public string MapCampaignName
        {
            get { return _campaignNameQS; }
            set { _campaignNameQS = value; }
        }

        /// <summary>
        /// Querystring item name to differentiate ads or links that point to the same URL.
        /// </summary>
        public string MapCampaignContent
        {
            get { return _campaignContentQS; }
            set { _campaignContentQS = value; }
        }

        /// <summary>
        /// Querystring item name to note the keywords for this ad.
        /// </summary>
        public string MapCampaignTerm
        {
            get { return _campaignTermQS; }
            set { _campaignTermQS = value; }
        }

        /// <summary>
        /// Querystring item name to identify a medium such as email or cost-per-click.
        /// </summary>
        public string MapCampaignMedium
        {
            get { return _campaignMediumQS; }
            set { _campaignMediumQS = value; }
        }

        /// <summary>
        /// Querystring item name to identify a search engine, newsletter name, or other source.
        /// </summary>
        public string MapCampaignSource
        {
            get { return _campaignSourceQS; }
            set { _campaignSourceQS = value; }
        }


        #endregion
    }
}
